package cn.com.bluemoon.daps.standard.service.impl;

import cn.com.bluemoon.daps.common.enums.DatabaseType;
import cn.com.bluemoon.daps.common.enums.StandardDataType;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.standard.entity.DapStandardDataType;
import cn.com.bluemoon.daps.standard.mapper.DapStandardDataTypeMapper;
import cn.com.bluemoon.daps.standard.service.DapStandardDataTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 数据库字段基础类型数据表 服务实现类
 * </p>
 *
 * @author admin
 * @since 2020-08-07
 */
@Slf4j
@Service
public class DapStandardDataTypeServiceImpl extends ServiceImpl<DapStandardDataTypeMapper, DapStandardDataType> implements DapStandardDataTypeService {
    /**
     * 本地缓存，带超时ttl
     */
    private static final Cache<DatabaseType, Map<Integer, Set<DapStandardDataType>>> DBTYPE_CACHE = CacheBuilder.<DatabaseType, Map<Integer, Set<String>>>newBuilder()
            .initialCapacity(10)
            .expireAfterAccess(1, TimeUnit.DAYS)
            .build();

    @Autowired
    DapStandardDataTypeMapper dapStandardDataTypeMapper;

    /**
     * 根据数据库及代码类型获得数据类型
     *
     * @param dbType
     * @param codeType
     * @return
     */
    @Override
    public List<String> getList(Integer dbType, Integer codeType) {

        List<String> list = dapStandardDataTypeMapper.selectTypeList(dbType, codeType);
        return list;

    }

    /**
     * 获取数据，缓存
     *
     * @param databaseType
     * @return
     */
    @Override
    public Map<Integer, Set<String>> getMapDataTypeByDbType(DatabaseType databaseType) {
        Map<Integer, Set<DapStandardDataType>> dbTypeAndStdDataTypeSet = getDbTypeAndStdDataTypeSetOnCache(databaseType);
        return dbTypeAndStdDataTypeSet.entrySet().stream().flatMap(e -> new HashMap<Integer, Set<String>>() {{
            put(e.getKey(), e.getValue().stream().map(DapStandardDataType::getCode).collect(Collectors.toSet()));
        }}.entrySet().stream()).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    }

    /**
     * 获取某个数据库下的标准类型的默认值
     *
     * @param dbType      d
     * @param stdDataType d
     * @return 获取某个数据库下的标准类型的默认值
     */
    @Override
    public Optional<String> getDefaultValByDbTypeAndCodeOnCache(DatabaseType dbType, StandardDataType stdDataType) {
        if (dbType == null || stdDataType == null) {
            return Optional.empty();
        }
        Map<Integer, Set<DapStandardDataType>> dbTypeAndStdDataTypeSet = getDbTypeAndStdDataTypeSetOnCache(dbType);
        Set<DapStandardDataType> dapStandardDataTypes = dbTypeAndStdDataTypeSet.getOrDefault(stdDataType.getCode(), Collections.emptySet());
        return dapStandardDataTypes.stream().filter(Objects::nonNull).map(DapStandardDataType::getDefaultVal).filter(StringUtils::isNotBlank).findFirst();
    }

    /**
     * 初始化+缓存+定时刷新
     *
     * @param databaseType 数据库类型
     * @return 获取数据库类型下的标准代码对应的字段类型信息
     */
    private Map<Integer, Set<DapStandardDataType>> getDbTypeAndStdDataTypeSetOnCache(DatabaseType databaseType) {
        BmAssetUtils.notNull(databaseType, "数据库类型不可为空");
        try {
            return DBTYPE_CACHE.get(databaseType, () -> {
                int dbType = databaseType.getCode();
                List<DapStandardDataType> list = list(bmLambdaQuery().eq(DapStandardDataType::getDbType, dbType));
                Map<Integer, Set<DapStandardDataType>> collect = list.stream()
                        .filter(d -> d != null && d.getCodeType() != null)
                        .collect(Collectors.groupingBy(DapStandardDataType::getCodeType,
                                Collectors.mapping(d -> d, Collectors.toSet())));
                log.info("初始化db:{},数据类型：{}", databaseType, list.size());
                return collect;
            });
        } catch (ExecutionException e) {
            log.error("获取缓存数据类型数据失败，" + e.getMessage());
        }
        return Collections.emptyMap();
    }
}
